# This testcase is part of GDB, the GNU debugger.
#
# Copyright 2013-2015 Free Software Foundation, Inc.
#
# Contributed by Intel Corp. <christian.himpel@intel.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# check for btrace support
if { [skip_btrace_tests] } { return -1 }

# start inferior
standard_testfile
if [prepare_for_testing function_call_history.exp $testfile {} {debug}] {
    return -1
}
if ![runto_main] {
    return -1
}

# start btrace
gdb_test_no_output "record btrace"

# set bp after increment loop and continue
set bp_location [gdb_get_line_number "bp.1" $testfile.c]
gdb_breakpoint $bp_location
gdb_continue_to_breakpoint "cont to $bp_location" ".*$testfile.c:$bp_location.*"

proc rec_fun_all {} {
  gdb_test "record function-call-history 1" [multi_line \
    "1\tmain" \
    "2\tinc" \
    "3\tmain" \
    "4\tinc" \
    "5\tmain" \
    "6\tinc" \
    "7\tmain" \
    "8\tinc" \
    "9\tmain" \
    "10\tinc" \
    "11\tmain" \
    "12\tinc" \
    "13\tmain" \
    "14\tinc" \
    "15\tmain" \
    "16\tinc" \
    "17\tmain" \
    "18\tinc" \
    "19\tmain" \
    "20\tinc" \
    "21\tmain"]
}

# show function call history with unlimited size, we expect to see all 21 entries
gdb_test_no_output "set record function-call-history-size 0"
with_test_prefix "size unlimited" rec_fun_all

# show function call history with size of 21, we expect to see all 21 entries
gdb_test_no_output "set record function-call-history-size 21"
with_test_prefix "size 21" rec_fun_all

# show first 15 entries
gdb_test_no_output "set record function-call-history-size 15"
gdb_test "record function-call-history 1" [multi_line \
  "1\tmain" \
  "2\tinc" \
  "3\tmain" \
  "4\tinc" \
  "5\tmain" \
  "6\tinc" \
  "7\tmain" \
  "8\tinc" \
  "9\tmain" \
  "10\tinc" \
  "11\tmain" \
  "12\tinc" \
  "13\tmain" \
  "14\tinc" \
  "15\tmain"] "forward - 1"

# show last 6 entries
gdb_test "record function-call-history +" [multi_line \
  "16\tinc" \
  "17\tmain" \
  "18\tinc" \
  "19\tmain" \
  "20\tinc" \
  "21\tmain"] "forward - 2"

# moving further should not work
gdb_test "record function-call-history +" "At the end of the branch trace record\\." "forward - 3"

# make sure we cannot move any further a second time
gdb_test "record function-call-history +" "At the end of the branch trace record\\." "forward - 4"

# moving back showing the latest 15 function calls
gdb_test "record function-call-history -" [multi_line \
  "7\tmain" \
  "8\tinc" \
  "9\tmain" \
  "10\tinc" \
  "11\tmain" \
  "12\tinc" \
  "13\tmain" \
  "14\tinc" \
  "15\tmain" \
  "16\tinc" \
  "17\tmain" \
  "18\tinc" \
  "19\tmain" \
  "20\tinc" \
  "21\tmain"] "backward - 1"

# moving further back shows the 6 first function calls
gdb_test "record function-call-history -" [multi_line \
  "1\tmain" \
  "2\tinc" \
  "3\tmain" \
  "4\tinc" \
  "5\tmain" \
  "6\tinc"] "backward - 2"

# moving further back shouldn't work
gdb_test "record function-call-history -" "At the start of the branch trace record\\." "backward - 3"

# make sure we cannot move any further back
gdb_test "record function-call-history -" "At the start of the branch trace record\\." "backward - 4"

# don't mess around with path names
gdb_test_no_output "set filename-display basename"

# moving forward again, but this time with file and line number, expected to see the first 15 entries
gdb_test "record function-call-history /l +" [multi_line \
  "\[0-9\]*\tmain\tat $srcfile:40,41" \
  "\[0-9\]*\tinc\tat $srcfile:22,24" \
  "\[0-9\]*\tmain\tat $srcfile:40,41" \
  "\[0-9\]*\tinc\tat $srcfile:22,24" \
  "\[0-9\]*\tmain\tat $srcfile:40,41" \
  "\[0-9\]*\tinc\tat $srcfile:22,24" \
  "\[0-9\]*\tmain\tat $srcfile:40,41" \
  "\[0-9\]*\tinc\tat $srcfile:22,24" \
  "\[0-9\]*\tmain\tat $srcfile:40,41" \
  "\[0-9\]*\tinc\tat $srcfile:22,24" \
  "\[0-9\]*\tmain\tat $srcfile:40,41" \
  "\[0-9\]*\tinc\tat $srcfile:22,24" \
  "\[0-9\]*\tmain\tat $srcfile:40,41" \
  "\[0-9\]*\tinc\tat $srcfile:22,24" \
  "\[0-9\]*\tmain\tat $srcfile:40,41" \
  ] "forward /l - 1"

# moving forward and expect to see the latest 6 entries
gdb_test "record function-call-history /l +" [multi_line \
  "\[0-9\]*\tinc\tat $srcfile:22,24" \
  "\[0-9\]*\tmain\tat $srcfile:40,41" \
  "\[0-9\]*\tinc\tat $srcfile:22,24" \
  "\[0-9\]*\tmain\tat $srcfile:40,41" \
  "\[0-9\]*\tinc\tat $srcfile:22,24" \
  "\[0-9\]*\tmain\tat $srcfile:40,43" \
  ] "forward /l - 2"

# moving further forward shouldn't work
gdb_test "record function-call-history /l +" "At the end of the branch trace record\\." "forward /l - 3"
gdb_test "record function-call-history /l" "At the end of the branch trace record\\." "forward /l - 4"

set expected_range [multi_line \
  "4\tinc" \
  "5\tmain" \
  "6\tinc" \
  "7\tmain" \
  "8\tinc" \
  "9\tmain" \
  "10\tinc"]

# show functions in instruction range
gdb_test "record function-call-history 4,10" $expected_range
gdb_test "record function-call-history 4,+7" $expected_range
gdb_test "record function-call-history 10,-7" $expected_range
gdb_test "record function-call-history 4,4" "4\tinc\r"

# set bp after fib recursion and continue
set bp_location [gdb_get_line_number "bp.2" $testfile.c]
gdb_breakpoint $bp_location
gdb_continue_to_breakpoint "cont to $bp_location" ".*$testfile.c:$bp_location.*"

# at this point we expect to have main, fib, ..., fib, main, where fib occurs 9 times,
# so we limit the output to only show the latest 11 function calls
gdb_test_no_output "set record function-call-history-size 11"
gdb_test "record function-call-history" [multi_line \
  "21\tmain" \
  "22\tfib" \
  "23\tfib" \
  "24\tfib" \
  "25\tfib" \
  "26\tfib" \
  "27\tfib" \
  "28\tfib" \
  "29\tfib" \
  "30\tfib" \
  "31\tmain"] "recursive"

# show indented function call history for fib
gdb_test "record function-call-history /c 21, +11" [multi_line \
  "21\tmain" \
  "22\t  fib" \
  "23\t    fib" \
  "24\t  fib" \
  "25\t    fib" \
  "26\t      fib" \
  "27\t    fib" \
  "28\t      fib" \
  "29\t    fib" \
  "30\t  fib" \
  "31\tmain" \
  ] "indented"

# make sure we can handle incomplete trace with respect to indentation
if ![runto_main] {
    return -1
}
# navigate to the fib in line 24 above
gdb_breakpoint fib
gdb_continue_to_breakpoint "cont to fib.1"
gdb_continue_to_breakpoint "cont to fib.2"
gdb_continue_to_breakpoint "cont to fib.3"
gdb_continue_to_breakpoint "cont to fib.4"

# start tracing
gdb_test_no_output "record btrace"

# continue until line 30 above
delete_breakpoints
set bp_location [gdb_get_line_number "bp.2" $testfile.c]
gdb_breakpoint $bp_location
gdb_continue_to_breakpoint "cont to bp.2" ".*$testfile.c:$bp_location\r\n.*"

# let's look at the trace. we expect to see the tail of the above listing.
gdb_test "record function-call-history /c" [multi_line \
  "1\t      fib" \
  "2\t    fib" \
  "3\t      fib" \
  "4\t    fib" \
  "5\t  fib" \
  "6\tmain" \
  ] "indented tail"
